/*
 * Copyright 2008 the Breachwalls OSS project and the Others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.breachwalls.quasar.datatype.converter;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.apache.commons.lang.ArrayUtils;

import com.breachwalls.quasar.datatype.Datatype;
import com.breachwalls.quasar.datatype.generic.GenericString;

/**
 * 汎用文字列型データタイプコンバータ.
 * @author todoken
 * @version $Revision: 37 $
 */
public class GenericStringConverter implements DatatypeConverter {

    /**
     * 文字列型SQLタイプ.
     */
    private static final int[] SQL_TYPES = new int[] {Types.VARCHAR };

    /**
     * 変換をサポートしているデータタイプのスーパークラス.
     */
    private static final Class<GenericString> SUPPORTED_DATATYPE = GenericString.class;

    /**
     * 変換するデータタイプクラス.
     */
    private Class<?> clazz;

    /**
     * コンストラクタ.
     * @param clazz 変換するデータタイプのクラス
     */
    public GenericStringConverter(Class<?> clazz) {
        this.clazz = clazz;
    }

    /**
     * このデータタイプコンバータが引数のデータタイプの変換をサポートしているかチェックする.
     * @param clazz チェックしたいデータタイプのクラス
     * @return サポートしていればTRUEを返す
     */
    public static boolean isSupported(Class<?> clazz) {
        return SUPPORTED_DATATYPE.isAssignableFrom(clazz);
    }

    /**
     * {@inheritDoc}
     */
    public Class<?> getConvertedClass() {
        return clazz;
    }

    /**
     * {@inheritDoc}
     */
    public int[] getSqlTypes() {
        return ArrayUtils.clone(SQL_TYPES);
    }

    /**
     * {@inheritDoc}
     */
    public Datatype nullSafeGet(ResultSet rs, String name) throws SQLException {
        final String v = rs.getString(name);
        if (!rs.wasNull()) {
            try {
                Constructor<?> c = clazz.getConstructor(String.class);
                return (Datatype) c.newInstance(v);
            } catch (ClassCastException e) {
                throw new DatatypeCreationException(e);
            } catch (NoSuchMethodException e) {
                throw new DatatypeCreationException(e);
            } catch (InstantiationException e) {
                throw new DatatypeCreationException(e);
            } catch (IllegalAccessException e) {
                throw new DatatypeCreationException(e);
            } catch (InvocationTargetException e) {
                throw new DatatypeCreationException(e);
            }
        }
        return null;
    }

    /**
     * {@inheritDoc}
     */
    public void nullSafeSet(PreparedStatement st, Object value, int index) throws SQLException {
        if (value == null) {
            st.setNull(index, Types.VARCHAR);
        } else {
            GenericString v = (GenericString) value;
            st.setString(index, v.toString());
        }
    }

}
